package com.sharer.last.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sharer.last.base.enums.BusinessExceptionCode;
import com.sharer.last.base.enums.ExceptionPrefixParamEnum;
import com.sharer.last.base.exception.BusinessException;
import com.sharer.last.base.model.PageVO;
import com.sharer.last.base.support.QueryCondition;
import com.sharer.last.base.utils.ConvertUtil;
import com.sharer.last.exception.PersistenceException;
import com.sharer.last.mapper.ScheduleJobLogMapper;
import com.sharer.last.mapper.ScheduleJobMapper;
import com.sharer.last.model.dto.schedule.ScheduleJobChangeDTO;
import com.sharer.last.model.dto.schedule.ScheduleJobQueryDTO;
import com.sharer.last.model.po.ScheduleJobPO;
import com.sharer.last.model.po.ScheduleJobLogPO;
import com.sharer.last.model.vo.ScheduleJobVO;
import com.sharer.last.service.ScheduleJobService;
import com.sharer.last.utils.BeanUtil;
import com.sharer.last.utils.quartz.ScheduleUtils;
import com.sharer.last.wrapper.ScheduleJobWrapper;
import org.quartz.CronTrigger;
import org.quartz.Scheduler;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;

/**
 * 定时任务业务层实现
 *
 * @ClassName ScheduleJobServiceImpl
 * @Author wangjin
 * @Date 2023/5/5 20:45
 * @Description
 * @Version 1.0
 */
@Service
public class ScheduleJobServiceImpl extends ServiceImpl<ScheduleJobMapper, ScheduleJobPO> implements ScheduleJobService {
    @Resource
    Scheduler scheduler;

    @Resource
    ScheduleJobMapper schedulerJobMapper;

    @Resource
    ScheduleJobWrapper scheduleJobWrapper;

    @Resource
    ScheduleJobLogMapper scheduleJobLogMapper;

    /**
     * 项目启动时，初始化定时器
     */
    @PostConstruct
    public void init() {
        List<ScheduleJobPO> scheduleJobList = this.list();
        for (ScheduleJobPO scheduleJob : scheduleJobList) {
            CronTrigger cronTrigger = ScheduleUtils.getCronTrigger(scheduler, scheduleJob.getId());
            //如果不存在，则创建
            if (cronTrigger == null) {
                ScheduleUtils.createScheduleJob(scheduler, scheduleJob);
            } else {
                ScheduleUtils.updateScheduleJob(scheduler, scheduleJob);
            }
        }
    }

    /**
     * 查询定时任务
     *
     * @return
     */
    @Override
    public List<ScheduleJobPO> queryList() {
        LambdaQueryWrapper<ScheduleJobPO> qw = new LambdaQueryWrapper<>();

        List<ScheduleJobPO> list = this.list(qw);
        return list;
    }

    /**
     * 分页查询
     *
     * @param queryDTO
     * @return
     */
    @Override
    public PageVO<ScheduleJobVO> selectListByPage(ScheduleJobQueryDTO queryDTO) {
        LambdaQueryWrapper<ScheduleJobPO> qw   = this.buildQueryWrapper(queryDTO);
        IPage<ScheduleJobPO>              page = this.page(QueryCondition.getPage(queryDTO.getPage()), qw);
        return scheduleJobWrapper.toPageVO(page);
    }

    private LambdaQueryWrapper<ScheduleJobPO> buildQueryWrapper(ScheduleJobQueryDTO queryDTO) {
        LambdaQueryWrapper<ScheduleJobPO> qw        = new LambdaQueryWrapper<>();
        String                            startTime = queryDTO.getStartTime();
        if (startTime != null) {
            qw.gt(ScheduleJobPO::getCreateTime, startTime);
        }
        String endTime = queryDTO.getEndTime();
        if (endTime != null) {
            qw.lt(ScheduleJobPO::getCreateTime, endTime);
        }
        return qw;
    }

    /**
     * 创建定时任务
     *
     * @param dto
     */
    @Override
    public void createJob(ScheduleJobChangeDTO dto) {
        ScheduleJobPO po = BeanUtil.copy(dto, ScheduleJobPO.class);
        if (!this.save(po)) {
            throw new BusinessException(BusinessExceptionCode.DATA_INSERT_FAIL, ExceptionPrefixParamEnum.SCHEDULE_JOB);
        }
    }

    /**
     * 更新定时任务
     *
     * @param dto
     */
    @Override
    public void updateJob(ScheduleJobChangeDTO dto) {
        Long id = dto.getId();
        if (ConvertUtil.toInt(id) < 1) {
            throw new BusinessException(BusinessExceptionCode.ID_IS_NULL, ExceptionPrefixParamEnum.SCHEDULE_JOB);
        }
        ScheduleJobPO scheduleJobPO = this.getById(id);
        if (scheduleJobPO == null) {
            throw new BusinessException(BusinessExceptionCode.DATA_IS_EMPTY, ExceptionPrefixParamEnum.SCHEDULE_JOB);
        }
        ScheduleJobPO scheduleJob = BeanUtil.copy(dto, ScheduleJobPO.class);
        if (!this.updateById(scheduleJob)) {
            throw new BusinessException(BusinessExceptionCode.DATA_UPDATE_FAIL, ExceptionPrefixParamEnum.SCHEDULE_JOB);
        }
    }

    /**
     * 更新定时任务状态
     *
     * @param id
     * @param status
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateJobStatusById(Long id, Integer status) {
        if (ConvertUtil.toInt(id) < 1) {
            throw new BusinessException(BusinessExceptionCode.ID_IS_NULL, ExceptionPrefixParamEnum.SCHEDULE_JOB);
        }
        ScheduleJobPO scheduleJobPO = this.getById(id);
        if (scheduleJobPO == null) {
            throw new BusinessException(BusinessExceptionCode.DATA_IS_EMPTY, ExceptionPrefixParamEnum.SCHEDULE_JOB);
        }
        if (status == 1) {
            ScheduleUtils.resumeJob(scheduler, id);
        } else {
            ScheduleUtils.pauseJob(scheduler, id);
        }
        ScheduleJobPO scheduleJob = ScheduleJobPO.builder()
                .id(id)
                .status(status)
                .build();
        if (!this.updateById(scheduleJob)) {
            throw new BusinessException(BusinessExceptionCode.DATA_UPDATE_FAIL, ExceptionPrefixParamEnum.SCHEDULE_JOB);
        }
    }

    /**
     * 删除定时任务
     *
     * @param id
     */
    @Override
    public void removeJobById(Long id) {
        if (ConvertUtil.toInt(id) < 1) {
            throw new BusinessException(BusinessExceptionCode.ID_IS_NULL, ExceptionPrefixParamEnum.SCHEDULE_JOB);
        }
        ScheduleJobPO scheduleJobPO = this.getById(id);
        if (scheduleJobPO == null) {
            throw new BusinessException(BusinessExceptionCode.DATA_IS_EMPTY, ExceptionPrefixParamEnum.SCHEDULE_JOB);
        }
        if (!this.removeById(id)) {
            throw new BusinessException(BusinessExceptionCode.DATA_REMOVE_FAIL, ExceptionPrefixParamEnum.SCHEDULE_JOB);
        }

    }

    /**
     * 执行任务
     *
     * @param jobId
     */
    @Override
    public void runJobById(Long jobId) {
        ScheduleUtils.run(scheduler, this.getById(jobId));
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveJobLog(ScheduleJobLogPO jobLog) {
        if (scheduleJobLogMapper.saveJobLog(jobLog) != 1) {
            throw new PersistenceException("日志添加失败");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteJobLogByLogId(Long logId) {
        if (scheduleJobLogMapper.deleteJobLogByLogId(logId) != 1) {
            throw new PersistenceException("日志删除失败");
        }
    }
}
